import { _decorator, Animation, AudioClip, Collider2D, Component, Contact2DType, instantiate, IPhysics2DContact, math, Node, Prefab } from 'cc';
import { GameManager } from './GameManager';
import { EnemyManager } from './EnemyManager';
import { AudioMgr } from './AudioMgr';
const { ccclass, property } = _decorator;

export enum MoveDirection {
    Down,
    Horizontal
}

@ccclass('Enemy')
export class Enemy extends Component {

    private _type:number = 0;

    @property
    speed:number = 300;

    // 横向移动速度
    @property
    speedHorizontal:number = 100;

    @property(Animation)
    anim:Animation = null;

    @property
    hp:number = 1;
    @property
    mutationHp:number = 8;
    @property
    bestHp:number = 10;

    @property
    animHit:string = "";
    @property
    animDown:string = "";

    @property
    score:number = 10;

    collider:Collider2D = null;
    isDead:boolean = false;
    bulletParent:Node = null;

    @property(AudioClip)
    enemyDownAudio:AudioClip = null;

    @property(Prefab)
    enemyBullet1:Prefab = null;
    @property(Node)
    enemy1BulletP1:Node = null;
    @property
    enemy1BulletRate:number = 0.4;
    enemy1BulletTimer:number = 0;

    gameStage:number = 1;
    moveDirection:MoveDirection = MoveDirection.Down;
    horizontalMove:boolean = true;
    horizontalTimestamp:number = 0;
    beginDirection:number = 1;

    start() {
        this.collider = this.getComponent(Collider2D);
        if(this.collider) {
            this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }
        this.gameStage = GameManager.getInstance().getGameStage();
        this.bulletParent = this.node.getParent().getParent().getChildByName('BulletParent');

        if(this.gameStage == 2) {
            this.hp = this.mutationHp;
        } else if(this.gameStage == 3) {
            this.hp = this.bestHp;
        }
    }

    update(deltaTime: number) {
        switch(this.gameStage) {
            case 1:
                this.normalUpdate(deltaTime);
                break;
            case 2:
                if(this._type == 0) {
                    this.normalUpdate(deltaTime);
                } else if(this._type == 1) {
                    this.mutationUpdate(deltaTime);
                } else if(this._type == 2) {
                    this.normalUpdate(deltaTime);
                }
                break;
            case 3:
                if(this._type == 0) {
                    this.normalUpdate(deltaTime);
                } else if(this._type == 1) {
                    this.mutationUpdate(deltaTime);
                } else if(this._type == 2) {
                    this.normalUpdate(deltaTime);
                }
                break;
        }
    }

    normalUpdate(deltaTime: number) {
        if(this.hp > 0) {
            const p = this.node.position;
            this.node.setPosition(p.x, p.y - deltaTime*this.speed, p.z);
        }

        if(this.node.position.y < -580) {
            this.node.destroy();
        }
    }

    mutationUpdate(deltaTime: number) {
        if(this.hp > 0) {
            if(this.moveDirection == MoveDirection.Down) {
                // 纵向移动
                const p = this.node.position;
                let nodeY = p.y - deltaTime*this.speed;
                if(nodeY <= 200 && this.horizontalMove) {
                    nodeY = 200;
                    this.moveDirection = MoveDirection.Horizontal;

                    // 仅仅改变一次横向
                    this.horizontalMove = false;

                    // 随机向左或者向右移动
                    const direction = math.randomRangeInt(0, 2);
                    this.beginDirection = [-1, 1][direction];
                    this.horizontalTimestamp = new Date().getTime();
                }
                this.node.setPosition(p.x, nodeY, p.z);
            } else {
                // 横向移动
                const p = this.node.position;
                let nodeX = p.x + this.beginDirection*deltaTime*this.speedHorizontal;
                if(nodeX < -200) {
                    nodeX = -200;
                    this.beginDirection = 1;
                } else if (nodeX > 200) {
                    nodeX = 200;
                    this.beginDirection = -1;
                }
                this.node.setPosition(nodeX, p.y, p.z);
            }

            // 生成子弹
            this.enemy1BulletShoot(deltaTime);
        }

        if(this.node.position.y < -580) {
            this.node.destroy();
        }
    }

    enemy1BulletShoot(dt: number) {
        if(this.gameStage < 2 || this._type != 1) {
            return;
        }

        this.enemy1BulletTimer += dt;
        if(this.enemy1BulletTimer > this.enemy1BulletRate) {
            this.enemy1BulletTimer = 0;
            const enemy1Bullet = instantiate(this.enemyBullet1);

            this.bulletParent.addChild(enemy1Bullet);
            enemy1Bullet.setWorldPosition(this.enemy1BulletP1.worldPosition);

            // 获取player位置，并设置子弹角度
        }
    }

    // 其中otherCollider是碰撞的物体，可以用它判断碰撞到的东西是什么
    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
        const enemy = otherCollider.getComponent(Enemy);
        if(enemy) {
            // 仅仅在横向移动后发生碰撞中型飞机的，才向下移动
            if(enemy.getType() == 1 && (this.horizontalTimestamp < enemy.horizontalTimestamp 
                || enemy.horizontalTimestamp == 0)) {
                this.onEnemyContact();
            }
        } else {
            // 与子弹碰撞
            this.onBulletContact();
        }
    }

    onEnemyContact() {
        if(!this.horizontalMove) {
            this.moveDirection = MoveDirection.Down;
        }
    }

    onBulletContact() {
        this.hp -= 1;
        if(this.hp > 0) {
            this.anim.play(this.animHit);
        } else {
            this.anim.play(this.animDown);
        }
        
        if(this.hp <= 0) {
            this.dead();
        }
    }

    dead() {
        if(this.isDead) {
            return;
        }

        AudioMgr.inst.playOneShot(this.enemyDownAudio, 0.5);
        this.isDead = true;
        if(this.collider) {
            this.collider.enabled = false;
        }
        this.scheduleOnce(function() {
            this.node.destroy();
        }, 1); 
        
        GameManager.getInstance().addScore(this.score);
    }

    killSelf() {
        if(this.hp <= 0) {
            return;
        }

        this.anim.play(this.animDown);
        this.hp = 0;
        this.dead();
    }

    protected onDestroy(): void {
        if(this.collider) {
            this.collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        }
        EnemyManager.getInstance().removeEnemy(this.node);
    }

    public getType(): number {
        return this._type;
    }

    public setType(type:number): void{ 
        this._type = type;
    }
}

